(* Programme principal *)

open Format
open Lexing
open Lexer
open Parser
open Cub
open Ast

let usage = "usage: algony [options] <filename>.any"

let parse_only = ref false
let type_only = ref false 

let traceopt = ref false
let spec = 
  ["-parse-only", Arg.Set parse_only, "  stops after parsing";
   "-type-only", Arg.Set type_only, "  stops after typing";
   "-trace", Arg.Set traceopt,
   "  display the unsafe execution given in <filename>.trace \
(same directory or local directory)";
  ]

let compile_to_cubicle lb file = 
  let c = open_in file in
  lb := Lexing.from_channel c;
  let p = Parser.prog Lexer.token !lb in
  close_in c;
  if !parse_only then (Format.printf "parse ok@\n"; exit 0);
  let p = Typing.type_prog p in
  if !type_only then (Format.printf "typing ok@\n";exit 0);
  let c = Compile.compile_prog p in
  let output_file = (Filename.chop_suffix file ".any") ^ ".cub" in
  let out = open_out output_file in
  let outf = formatter_of_out_channel out in
  Cub.print_system outf c;
  pp_print_flush outf ();
  close_out out

let run_trace lb file trace_file =
  let c = open_in trace_file in
  lb := Lexing.from_channel c;
  let tr = Lextrace.trace !lb in
  close_in c;
  Trace.run tr file
    
let file =
  let file = ref None in
  let set_file s =
    if not (Filename.check_suffix s ".any") then
    raise (Arg.Bad "no .any extension");
    file := Some s
  in
  Arg.parse spec set_file usage;
  match !file with Some f -> f | None -> Arg.usage spec usage; exit 1

let trace_file =
  let trace_file = ref ((Filename.chop_suffix file ".any") ^ ".trace") in
  if !traceopt then
  if not (Sys.file_exists !trace_file) then begin
    let basename = Filename.basename !trace_file in
    if not (Sys.file_exists basename) then
    raise (Arg.Bad "no trace file (it must be in the same \
directory or local directory)")
    else trace_file := basename
  end;
  !trace_file
    
let report_loc_file (b,e) file =
  let l = b.pos_lnum in
  let fc = b.pos_cnum - b.pos_bol + 1 in
  let lc = e.pos_cnum - b.pos_bol + 1 in
  eprintf "File \"%s\", line %d, characters %d-%d:\n" file l fc lc            
let report_loc (b,e) = report_loc_file (b, e) file

  
let () =
  let lb = ref (Lexing.from_string "") in
  try
    if !traceopt then run_trace lb file trace_file
    else compile_to_cubicle lb file
  with
  | Lexer.Lexical_error s ->
      report_loc (lexeme_start_p !lb, lexeme_end_p !lb);
      eprintf "Lexical error : %s\n@." s;
      exit 1
  | Lextrace.Lexical_error s ->
      report_loc_file (lexeme_start_p !lb, lexeme_end_p !lb) trace_file;
      eprintf "Lexical error : %s\n@." s;
      exit 1
  | Typing.Error (e, loc) ->
      report_loc loc;
      Typing.print_error e; exit 1
  | Parsing.Parse_error ->
      report_loc (lexeme_start_p !lb, lexeme_end_p !lb);
      eprintf "Syntax error\n@.";
      exit 1
  | e ->
      report_loc (lexeme_start_p !lb, lexeme_end_p !lb);
      eprintf "Anomaly: %s\n@." (Printexc.to_string e);
      exit 2











